////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Michiel Helvensteijn                                    //
//                                                                            //
// This file is part of the Mist compiler.                                    //
//                                                                            //
// The Mist compiler is free software: you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by       //
// the Free Software Foundation, either version 3 of the License, or          //
// (at your option) any later version.                                        //
//                                                                            //
// The Mist compiler is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of             //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              //
// GNU General Public License for more details.                               //
//                                                                            //
// You should have received a copy of the GNU General Public License          //
// along with the Mist compiler.  If not, see <http://www.gnu.org/licenses/>. //
////////////////////////////////////////////////////////////////////////////////

#ifndef VISITOR_HPP
#define VISITOR_HPP

/******************************************************************************
 * Includes                                                                   *
 ******************************************************************************/

#include <vector>
using std::vector;

#include <string>
using std::string;

#include <boost/shared_ptr.hpp>
using boost::shared_ptr;

#include <boost/enable_shared_from_this.hpp>
using boost::enable_shared_from_this;

#include "path.hpp"
#include "messages.hpp"

class Node;
class Expression;
class ArithmeticOperation;
class FunctionCall;
class UnaryOperation;
class Identifier;
class BooleanLiteral;
class IntegerLiteral;
class Null;
class Type;
class ArrayType;
class IntegerType;
class BooleanType;
class Assertion;
class IfStatement;
class WhileStatement;
class Assignment;
class IdAssignment;
class CompoundStatement;
class FunctionType;
class VoidType;
class VariableDeclaration;
class FunctionDeclaration;
class Declarations;
class Subscripting;
class ComparisonChain;
class TypeError;
class AndChain;
class OrChain;
class ImpliesChain;
class ForStatement;
class Range;
class RangeType;
class Reference;
class BooleanPointerLiteral;
class IntegerPointerLiteral;

/******************************************************************************
 * Visitor Class                                                              *
 ******************************************************************************/

class Visitor : public enable_shared_from_this<Visitor> {
	public:
		
		virtual ~Visitor() { }
		
		virtual void visit(shared_ptr<ArithmeticOperation>)   { assert(false); }
		virtual void visit(shared_ptr<FunctionCall>)          { assert(false); }
		virtual void visit(shared_ptr<UnaryOperation>)        { assert(false); }
		virtual void visit(shared_ptr<Identifier>)            { assert(false); }
		virtual void visit(shared_ptr<IntegerLiteral>)        { assert(false); }
		virtual void visit(shared_ptr<BooleanLiteral>)        { assert(false); }
		virtual void visit(shared_ptr<Null>)                  { assert(false); }
		virtual void visit(shared_ptr<ArrayType>)             { assert(false); }
		virtual void visit(shared_ptr<IntegerType>)           { assert(false); }
		virtual void visit(shared_ptr<BooleanType>)           { assert(false); }
		virtual void visit(shared_ptr<Assertion>)             { assert(false); }
		virtual void visit(shared_ptr<IfStatement>)           { assert(false); }
		virtual void visit(shared_ptr<WhileStatement>)        { assert(false); }
		virtual void visit(shared_ptr<Assignment>)            { assert(false); }
		virtual void visit(shared_ptr<IdAssignment>)          { assert(false); }
		virtual void visit(shared_ptr<CompoundStatement>)     { assert(false); }
		virtual void visit(shared_ptr<FunctionType>)          { assert(false); }
		virtual void visit(shared_ptr<VoidType>)              { assert(false); }
		virtual void visit(shared_ptr<VariableDeclaration>)   { assert(false); }
		virtual void visit(shared_ptr<FunctionDeclaration>)   { assert(false); }
		virtual void visit(shared_ptr<Declarations>)          { assert(false); }
		virtual void visit(shared_ptr<Subscripting>)          { assert(false); }
		virtual void visit(shared_ptr<ComparisonChain>)       { assert(false); }
		virtual void visit(shared_ptr<TypeError>)             { assert(false); }
		virtual void visit(shared_ptr<AndChain>)              { assert(false); }
		virtual void visit(shared_ptr<OrChain>)               { assert(false); }
		virtual void visit(shared_ptr<ImpliesChain>)          { assert(false); }
		virtual void visit(shared_ptr<ForStatement>)          { assert(false); }
		virtual void visit(shared_ptr<Range>)                 { assert(false); }
		virtual void visit(shared_ptr<RangeType>)             { assert(false); }
		virtual void visit(shared_ptr<Reference>)             { assert(false); }
		virtual void visit(shared_ptr<BooleanPointerLiteral>) { assert(false); }
		virtual void visit(shared_ptr<IntegerPointerLiteral>) { assert(false); }
	
	protected: // functions
		
		Visitor(shared_ptr<Messages> messages = shared_ptr<Messages>());
		
		shared_ptr<Messages> messages() const;
	
	private:
		
		shared_ptr<Messages> _messages;
};

/******************************************************************************
 * ACCEPT_VISITOR Macro's                                                     *
 ******************************************************************************/

#define ACCEPT_VISITOR                           \
	public:                                       \
		                                           \
		void accept(shared_ptr<Visitor> visitor) {  \
				visitor->visit(shared_from_this());  \
		}

#define VIRTUAL_ACCEPT_VISITOR \
	public:                     \
		                         \
		virtual void accept(shared_ptr<Visitor> visitor) =0;

#endif // VISITOR_HPP
